package com.gitee.zhziyun.cnfsystem.works;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.gitee.zhziyun.cnfsystem.master.AppMaster;
import com.gitee.zhziyun.cnfsystem.model.UserInfo;
import com.gitee.zhziyun.cnfsystem.utils.udputil.UDPReceiver;
import com.gitee.zhziyun.cnfsystem.config.IpPortConfig;
import com.gitee.zhziyun.cnfsystem.model.Command;
import com.gitee.zhziyun.cnfsystem.utils.JSONUtil;
import com.gitee.zhziyun.cnfsystem.utils.udputil.UDPSender;

import javax.swing.Timer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

public class HeartBeatWorker implements Worker {
    private final AppMaster appMaster;                  // 与主服务通信接口
    private final Queue<String> messageQueue;           // 消息队列
    private final Map<String, UserInfo> ipUserMap;      // 在线用户表
    private final Map<String, Long> lastHeartbeatTimeMap; // 最后心跳时间记录

    private final Timer sendAliveTimer;                 // 定时发送心跳
    private final Timer cleanUserListTimer;             // 定时清理超时用户
    private final UDPReceiver messageReceiver;          // 消息接收器
    private final MessageHandler messageHandler;        // 消息处理器

    /**
     *  初始化
     * @param appMaster 与主服务通信接口
     */
    public HeartBeatWorker(AppMaster appMaster) {
        this.appMaster = appMaster;
        this.messageQueue = new ConcurrentLinkedQueue<>();
        this.ipUserMap = appMaster.getIpUserMap();
        this.lastHeartbeatTimeMap = new ConcurrentHashMap<>(); // 初始化心跳时间记录
        this.messageReceiver = new UDPReceiver(messageQueue, IpPortConfig.getHeartBeatPort());
        this.messageHandler = new MessageHandler();

        // 每3秒发送一条心跳，每2秒检查一次超时用户
        this.sendAliveTimer = new Timer(3000, e-> sendAlive());
        this.cleanUserListTimer = new Timer(2000, e -> cleanExpiredUsers());
    }

    @Override
    public void start() {
        messageReceiver.start();
        messageHandler.start();
        cleanUserListTimer.start();
        sendAliveTimer.start();
        sendAlive();
    }

    @Override
    public void stop() {
        sendAliveTimer.stop();
        cleanUserListTimer.stop();

        try {
            Command cmd = new Command("down", JSONUtil.objectToString(appMaster.getUserInfo()));
            UDPSender.send(IpPortConfig.getHeartBeatIp(), IpPortConfig.getHeartBeatPort(), JSONUtil.objectToString(cmd));
        } catch (Exception e){
            throw new RuntimeException(e);
        }

        messageReceiver.close();
        messageHandler.close();
    }

    /**
     * 发送心跳
     */
    private void sendAlive() {
        try {
            System.out.println("发送在线信息");
            Command cmd = new Command("alive", JSONUtil.objectToString(appMaster.getUserInfo()));
            UDPSender.send(IpPortConfig.getHeartBeatIp(), IpPortConfig.getHeartBeatPort(), JSONUtil.objectToString(cmd));
            System.out.println("在线用户列表：");
            for (Map.Entry<String, UserInfo> entry : ipUserMap.entrySet()) {
                System.out.println(entry.getKey() + ":" + JSONUtil.objectToString(entry.getValue()));
            }
        } catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    /**
     * 清理超时用户（7秒无心跳）
     */
    private void cleanExpiredUsers() {
        long currentTime = System.currentTimeMillis();
        // 收集需要移除的IP（避免遍历时修改Map）
        List<String> toRemove = new ArrayList<>();

        for (Map.Entry<String, Long> entry : lastHeartbeatTimeMap.entrySet()) {
            String ip = entry.getKey();
            long lastTime = entry.getValue();
            // 7秒无心跳视为超时
            if (currentTime - lastTime > 7000) {
                toRemove.add(ip);
            }
        }

        // 批量移除超时用户
        for (String ip : toRemove) {
            ipUserMap.remove(ip);
            lastHeartbeatTimeMap.remove(ip);
            appMaster.fireUserOffline(ip);
            System.out.println("移除超时用户: " + ip);
        }
    }

    private class MessageHandler extends Thread {
        private boolean running = true;
        @Override
        public void run() {
            while (running) {
                String message = messageQueue.poll();

                if (message != null) {
                    String[] parts = message.split(":", 2);
                    if (parts.length < 2) continue;  // 防止格式错误

                    try {
                        String senderIp = parts[0];
                        Command command = JSONUtil.stringToObject(parts[1], Command.class);
                        String option = command.getOption();

                        // 处理心跳消息
                        if ("alive".equals(option)) {
                            System.out.println("收到在线心跳: " + senderIp);
                            UserInfo userInfo = JSONUtil.stringToObject(command.getData(), UserInfo.class);

                            // 如果是新用户才触发上线事件
                            boolean isNew = !ipUserMap.containsKey(senderIp);
                            ipUserMap.put(senderIp, userInfo);
                            lastHeartbeatTimeMap.put(senderIp, System.currentTimeMillis());

                            if (isNew) {
                                appMaster.fireUserOnline(senderIp, userInfo);
                            }
                        }
                        // 处理下线消息（新增）
                        else if ("down".equals(option)) {
                            System.out.println("收到下线通知: " + senderIp);
                            ipUserMap.remove(senderIp);
                            lastHeartbeatTimeMap.remove(senderIp);

                            appMaster.fireUserOffline(senderIp);
                        }
                    } catch (JsonProcessingException e) {
                        System.err.println("JSON解析错误: " + e.getMessage());
                    } catch (Exception e) {
                        System.err.println("消息处理异常: " + e.getMessage());
                    }
                }
            }
        }
        public void close() {
            running = false;
        }
    }
}